Practical Monads

[[https://dl.dropboxusercontent.com/u/1150365/img/github.png]]

ToC

  • Monad
  • Promise
  • Observable
  • Demo

Monad

A monad is just a monoid in the category of endofunctors, what's the problem?

Before Monad

ES6 101

EcmaScript5

  function(x){return x+1}

EcmaScript6

  x=>x+1

Haskell 101

  --  HM(Hindley-Milner) type signature
  liftM :: (Monad m) => (a -> b) -> m a -> m b 
  --        ^type restrict ^function    ^  ^return
  --                              ^curry^   

Functional 101

  [1,2,3].map(x=>x+1)
  // => [2,3,4]
  [1,2,3].filter(x=>x/2==0)
  // => [2]
  [1,2,3].reduce((acc,n)=>acc+n)
  // => 6

instance of Functor, Monoid

a Array Functor

  ["hello", "world"].map(x=>x.toUpperCase())
  // => ["HELLO", "WORLD"]

functor is mapable!

a String Monoid

  "hello" + "world" // <-- concat
  // => "helloworld"
  "hello" + ""   // <--  identity
  // => "hello"
  ("hello" + "world") + "!" == "hello" + ("world" + "!") // <-- associative
  // => true

Monoid is concatable!

Functional 102

Method -> Function

  map(x=>x.toUpperCase(), ["hello", "world"])
  concat("hello", "world")
  concat("empty", "")

Substitution

A monad is just a monoid in the category of endofunctors, what's the problem?

  • Catergory -> "Type"
  • Functor -> "Mapable"
  • Monoid -> "Concatable"

"A monad is just a concatable in mapable Type, what's the problem?"

Type Monoid

concat -> flat

flat(Maybe[Maybe[(Maybe[T])]]) == flat(Maybe[(Maybe[Maybe[T]])])

join

join (Maybe[T]) == Maybe [Maybe[T]]

concat(Maybe[ Maybe[Maybe[T]] ]) == concat(join(Maybe[Maybe[T]])) == Maybe[Maybe[T]]

u -> flat

uT(x) -> flat(T(x))

T(ux) -> lift(flat, x)

n -> join

nT(x) -> join(T(x))

T(nx) -> map(join, T(x))

Some Useful Monad functions

lift

  liftM :: (Monad m) => (a -> b) -> m a -> m b 

  const when = require('when')
  let readJSON = when.lift(JSON.parse)
  readJSON(when('{hello: "world"}'))
      .then(x=>console.log(x))
      .catch(e=>console.error(e.message));
  // => Unexpected token h in JSON at position 1

as I said promise is smart monad

  readJSON('{"hello": "world"}')
      .then(x=>console.log(x))
      .catch(e=>console.error(e.message));
  // => { hello: 'world' }

try

or simply try something and wrap result in Promise

  try(JSON.parse, '{hello: "world"}')
        .then(x=>console.log(x))
        .catch(e=>console.error(e.message));
  // => Unexpected token h in JSON at position 1

fold

  foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a

Pratical Monad

Maybe

    const Type = require('union-type')
    const T = () => true;
    const Maybe = Type({Just: [T], Nothing: []});
    Maybe.prototype.map = function(fn) {
      return Maybe.case({
        Nothing: () => Maybe.Nothing(),
        Just: (v) => Maybe.Just(fn(v))
      }, this);
    };
  ...

Union Type == ADT(Algebraic Data Type)

Promise is a smart Monad

  let futureWorld = new Promise(resolve=>{
      setTimeout(()=>resolve("world"), 1000)
  })

  futureWorld
      .then(world=>new Promise(resolve=>{
          setTimeout(()=>resolve("hello"+world), 1000)
      }))
      .then(x=>console.log(x))
  // 2secs later => helloworld
  • first then is flatMap
  • second then is map

Observable

Observable

Space -> Time

FRP(Functional Reactive Programming)

Single Item Multiple Items
synchronous getData():T getData():List[T]
asynchronous getData():Future[T] getData():Observable[T]

ReactiveX

fold

flatMap

fromEvent

Demo

[[https://dl.dropboxusercontent.com/u/1150365/futurama/neat.gif]]

Fin

Thanks